#ifndef RAYTRACER_CU
#define RAYTRACER_CU

#include "Raytracer.h"

__global__ void renderPixel(RenderArgs* args, Scene* scene) {

	float3* imageData= args->d_imageData;

	int threadIndex = (threadIdx.y*blockDim.x + threadIdx.x);
	int pxlIndex = (blockIdx.y*gridDim.x + blockIdx.x);
	int uniqueIndex = pxlIndex * blockDim.x*blockDim.y + threadIndex;
	//generate this thread's only sample
	SampleRequest request = generateSample(args, scene->camera);

	//allocate some shared memory for each sample to store it's result
	__shared__ float3 sampleData[MAX_THREADS];


	//send the sample into the scene
	for(int m = 0; m<scene->modelCt; m++){
		SampleResult sres = scene->models[m]->sample(request);
		sampleData[threadIndex] = sres.color.toFloat3();
	}


	//after all threads complete, average the results
	__syncthreads();
	float3 total = make_float3(0.0f, 0.0f, 0.0f);
	for (int i = 0; i<blockDim.y; i++){
		for(int j = 0; j<blockDim.x; j++){
			total.x += sampleData[i*blockDim.y+j].x;
			total.y += sampleData[i*blockDim.y+j].y;
			total.z += sampleData[i*blockDim.y+j].z;
		}
	}
	total.x = total.x / blockDim.x*blockDim.y;
	total.y = total.y / blockDim.x*blockDim.y;
	total.z = total.z / blockDim.x*blockDim.y;	

	int dataX = blockIdx.x;
	int dataY = (gridDim.y - blockIdx.y - 1);
	int dataIndex = dataX + (gridDim.x * dataY);

	imageData[dataIndex].x = total.x;
	imageData[dataIndex].y = total.y;
	imageData[dataIndex].z = total.z;
}

__device__  void renderSample(SampleRequest* request){
	//create a sampleRequest
	//for(passLimit) {
	//	send request
	//	mix color
	//	if (newRequest of weight above threshold){
	//		loop
	//	}
	//}

}

__device__  SampleRequest generateSample(RenderArgs* args, Camera* camera){
	int rOff = threadIdx.x*threadIdx.y;
	SampleRequest request = SampleRequest();
	request.pixel.x = blockIdx.x;
	request.pixel.y = blockIdx.y;
	request.sample.x = threadIdx.x;
	request.sample.y = threadIdx.y;
	request.tMax = FLT_MAX;
	request.tMin = 0;
	request.weight = 1.0;

	int xResolution = args->imageResolution.x;
    int yResolution = args->imageResolution.y;
    int x = blockIdx.x;
    int y = blockIdx.y;

    float left, top, frameWidth, frameHeight;
    frameWidth = camera->planeWidth;
    frameHeight = frameWidth / ((float)xResolution/(float)yResolution);
    left = -frameWidth/2.0;
    top = -frameHeight/2.0;

    float pxlWidth = frameWidth/xResolution;
    float pxlHeight = frameHeight/yResolution;

    float directionX, directionY, directionZ;
    //left edge + x pixels + half a pixel
    directionX = left + pxlWidth*(x+0.5);
    //top edge + y pixels + half a pixel
    directionY = top + pxlHeight*(y+0.5);
    directionZ = -camera->focalLength;
    Vector3 pixelCenter;

    //if we want 1 sample, just return one ray through the center
    if(args->sampleResolution.x * args->sampleResolution.y == 1){
        pixelCenter.normalize();
		request.ray = Ray(camera->origin, pixelCenter);
    }
    //otherwise, jitter them evenly over the pixel
	float subPixelWidth = pxlWidth/args->sampleResolution.x;
	float subPixelHeight = pxlHeight/args->sampleResolution.y;
    
        float xOffset = (0.5f/RAND_MAX)*subPixelWidth;
        float yOffset = (0.5f/RAND_MAX)*subPixelHeight;
        int sp_row = threadIdx.y;
        int sp_col = threadIdx.x;
        float sp_x = left + x*pxlWidth + threadIdx.x*subPixelWidth + xOffset;
        float sp_y = top + y*pxlHeight + threadIdx.y*subPixelHeight + yOffset;

		//this is for depth of field, NOT SUPPORTED YET
        ////a random point on the lense

        //float theta = ((i/(float)gParams.initialSamples) +
        //                (random() * (1.0/gParams.initialSamples)/(float)RAND_MAX))
        //                *2*M_PI;

        ////lense size is diameter of lense
        ////nth root pushes radius towards 1
        ////this counter's the algorithm's tendancy
        ////to favor the center of the circle

        //float radius = pow((random()/(float)RAND_MAX), (.5))*camera->lenseSize*0.5;

        //float lenseX = cos(theta)*radius;
        //float lenseY = sin(theta)*radius;

        //Vector3 sampleOrigin = camera->origin + (camera.u * lenseX) + (camera.v * lenseY);

		//END DoF code

		Vector3 sampleOrigin = camera->origin;

        //this is the 3D point the ray will pass through the image plane at
        Vector3 planePoint = Vector3((camera->u * sp_x) + (camera->v * sp_y) + (camera->w * -camera->focalLength) + camera->origin);
        Vector3 sampleDirection = planePoint - sampleOrigin;
		request.ray = Ray(sampleOrigin, sampleDirection.normalize());
		return request;
    
	//END OLD

}

#endif
